package com.yunwaikeji.gy_tool_library.utils.display;

import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.media.FaceDetector;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.view.View;

import androidx.core.graphics.drawable.DrawableCompat;

import com.yunwaikeji.gy_tool_library.info.GYDisplayInfo;
import com.yunwaikeji.gy_tool_library.model.GYResultModel;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 处理各种drawable、bitmap、picture、image
 */
public class GYDisplayUtils implements GYDisplayInfo {
    private static void error(String error) {
        Log.e("GYDisplayUtils", error);
    }

    public static GYPathBuilder newPathBuilder(float width, float height) {
        return new GYPathBuilder(width, height);
    }

    public static GYDisplayBuilder newBuilder() {
        return new GYDisplayBuilder();
    }

    /**
     * 着色器
     *
     * @param drawable
     * @param colors
     * @return
     */
    public static Drawable tintDrawable(Drawable drawable, ColorStateList colors) {
        //给相应的drawable着色（v4包中的DrawableCompat着色）
        final Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
        DrawableCompat.setTintList(wrappedDrawable, colors);
        return wrappedDrawable;
    }

    /**
     * 获取颜色
     *
     * @param drawable
     * @return
     */
    public static List<Integer> getColorList(Drawable drawable) {
        List<Integer> colorList = new ArrayList<>();
        if (drawable != null) {
            if (drawable instanceof ColorDrawable) {
                colorList.add(((ColorDrawable) drawable).getColor());
            } else if (drawable instanceof StateListDrawable) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    StateListDrawable stateListDrawable = (StateListDrawable) drawable;
                    for (int i = 0; i < stateListDrawable.getStateCount(); i++) {
                        colorList.addAll(getColorList(stateListDrawable.getStateDrawable(i)));
                    }
                }
            }
        }
        return colorList;
    }

    /**
     * 获取默认色
     *
     * @param drawable
     * @return
     */
    public static int getNormalColor(Drawable drawable) {
        List<Integer> colorList = getColorList(drawable);
        if (!colorList.isEmpty()) {
            return colorList.get(0);
        }
        return Color.TRANSPARENT;
    }

    /**
     * bitmap转drawable
     *
     * @param bitmap
     * @return
     */
    public static Drawable toDrawable(Bitmap bitmap) {
        return new BitmapDrawable(bitmap);
    }

    /**
     * drawable转bitmap
     *
     * @param drawable
     * @return
     */
    public static Bitmap toBitmap(Drawable drawable) {
        //获取图片宽度
        int width = drawable.getIntrinsicWidth();
        //获取图片高度
        int height = drawable.getIntrinsicHeight();
        return toBitmap(drawable, width, height);
    }

    public static Bitmap toBitmap(Drawable drawable, int width, int height) {
        //声明将要创建的bitmap
        Bitmap bitmap = null;
        //图片位深，PixelFormat.OPAQUE代表没有透明度，RGB_565就是没有透明度的位深，否则就用ARGB_8888。详细见下面图片编码知识。
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
        //创建一个空的Bitmap
        bitmap = Bitmap.createBitmap(width, height, config);
        //在bitmap上创建一个画布
        Canvas canvas = new Canvas(bitmap);
        //设置画布的范围
        drawable.setBounds(0, 0, width, height);
        //将drawable绘制在canvas上
        drawable.draw(canvas);
        return bitmap;
    }

    public static Bitmap getBitmap(String path, int reqWidth, int reqHeight) {
        // First decode with inJustDecodeBounds=true to check dimensions
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;//如此，无法decode bitmap
        BitmapFactory.decodeFile(path, options);
        // Calculate inSampleSize
        options.inSampleSize = getInSampleSize(options, reqWidth, reqHeight);
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;//如此，方可decode bitmap
        return BitmapFactory.decodeFile(path, options);
    }

    //计算采样率
    public static int getInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int width = options.outWidth;
        final int height = options.outHeight;
        int inSampleSize = 1;
        while (width / inSampleSize > reqWidth || height / inSampleSize > reqHeight) {
            inSampleSize++;
        }
//        if (height > reqHeight || width > reqWidth) {
//            final int halfHeight = height / 2;
//            final int halfWidth = width / 2;
//            while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
//                inSampleSize *= 2;
//            }
//        }
        return inSampleSize;
    }

    public static int getBitmapSize(Bitmap bitmap) {
        if (bitmap == null) {
            return 0;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //api 19
            return bitmap.getAllocationByteCount();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { //api 12
            return bitmap.getByteCount();
        }
        return bitmap.getRowBytes() * bitmap.getHeight(); //other version
    }

    /**
     * 检测bitmap中的人脸数量
     *
     * @param bitmap
     */
    public static int getFaceNumber(Bitmap bitmap, int maxFaces) {
        if (bitmap == null) {
            return 0;
        }
        try {
            FaceDetector faceDetector = new FaceDetector(bitmap.getWidth(), bitmap.getHeight(), maxFaces);
            FaceDetector.Face[] faces = new FaceDetector.Face[maxFaces];
            return faceDetector.findFaces(bitmap, faces);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    public static int getFaceNumber(Bitmap bitmap) {
        return getFaceNumber(bitmap, 1);
    }


    /**
     * 保存View至本地SD
     *
     * @param view 布局
     * @param path 路径
     * @param name 名称
     * @return
     */
    public static GYResultModel<String> saveToSD(View view, String path, String name) {
        return saveToSD(toBitmap(view), path, name, Bitmap.CompressFormat.PNG);
    }

    /**
     * 保存图片至本地SD
     *
     * @param bitmap 布局
     * @param path   路径
     * @param name   名称
     * @return
     */
    public static GYResultModel<String> saveToSD(Bitmap bitmap, String path, String name) {
        return saveToSD(bitmap, path, name, Bitmap.CompressFormat.PNG);
    }

    /**
     * 保存图片至本地SD
     *
     * @param bitmap
     * @param path           路径
     * @param name           名称
     * @param compressFormat 图片格式
     * @return
     */
    public static GYResultModel<String> saveToSD(Bitmap bitmap, String path, String name, Bitmap.CompressFormat compressFormat) {
        FileOutputStream fileOutputStream;
        File file = new File(path);
        if (!file.exists()) {
            if (!file.mkdirs()) {
                error("创建文件夹失败：" + file);
            }
        }
        String fileName = file + File.separator + name;// 图片名字
        try {
            fileOutputStream = new FileOutputStream(fileName);
            bitmap.compress(compressFormat, 100, fileOutputStream);// 把数据写入文件
            // 关闭流
            fileOutputStream.flush();
            fileOutputStream.close();
            return new GYResultModel<String>().setSuccess(true).setData(fileName);
        } catch (FileNotFoundException e) {
            error("保存文件错误：FileNotFoundException：" + e.toString());
            e.printStackTrace();
            return new GYResultModel<String>().setSuccess(false).setMsg("FileNotFoundException：" + e.toString());
        } catch (IOException e) {
            error("保存文件错误：IOException：" + e.toString());
            return new GYResultModel<String>().setSuccess(false).setMsg("IOException：" + e.toString());
        }
    }

    /**
     * view转bitmap
     */
    public static Bitmap toBitmap(View view) {
        return toBitmap(view, view.getWidth(), view.getHeight());
    }

    /**
     * view转bitmap
     */
    public static Bitmap toBitmap(View view, int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(Color.WHITE);
        /** 如果不设置canvas画布为白色，则生成透明 */
        view.layout(0, 0, width, height);
        view.draw(canvas);
        return bitmap;
    }

    /**
     * 保存图片至系统相册
     */
    public static GYResultModel<String> saveToSystemAlbum(Context context, Bitmap bitmap, String name) {
        Log.d("test", "Build.BRAND============" + Build.BRAND);
        String fileName;
        File file;
        if (Build.BRAND.equals("xiaomi")) { // 小米手机
            fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/" + name;
        } else if (Build.BRAND.equals("Huawei")) {
            fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/" + name;
        } else {  // Meizu 、Oppo
            fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/" + name;
        }
        file = new File(fileName);

        FileOutputStream out;
        try {
            out = new FileOutputStream(file);
            // 格式为 JPEG，照相机拍出的图片为JPEG格式的，PNG格式的不能显示在相册中
            if (bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)) {
                out.flush();
                out.close();
                // 插入图库
                MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), name, null);
            }
            // 发送广播，通知刷新图库的显示
            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + fileName)));
            if (file.exists()) {
                file.delete();
            }
            return new GYResultModel<String>().setSuccess(true);
        } catch (IOException e) {
            e.printStackTrace();
            return new GYResultModel<String>().setSuccess(false).setMsg(e.toString());
        }
    }

    public static Bitmap getBitmap(Context context, int resId) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        InputStream is = context.getResources().openRawResource(resId);
        return BitmapFactory.decodeStream(is, null, opt);
    }

    public static byte[] getByte(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(format, quality, baos);
        try {
            baos.flush();
            baos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return baos.toByteArray();
    }

    public static byte[] getByte(Bitmap bitmap, Bitmap.CompressFormat format) {
        return getByte(bitmap, format, 100);
    }

    public static byte[] getByte(Bitmap bitmap) {
        return getByte(bitmap, Bitmap.CompressFormat.PNG, 100);
    }

    public static Bitmap getBitmap(String path) {
        try {
            FileInputStream fis = new FileInputStream(path);
            Bitmap bitmap = BitmapFactory.decodeStream(fis);
            fis.close();
            return bitmap;  ///把流转化为Bitmap图片
        } catch (Exception e) {
            e.printStackTrace();
            error(e.toString());
            return null;
        }
    }

    public static Drawable getDrawable(String path) {
        return new BitmapDrawable(getBitmap(path));
    }

    public static Bitmap getBitmapByWidth(Bitmap bitmap, int width) {
        if (bitmap != null) {
            float mWidth = bitmap.getWidth();
            float mHeight = bitmap.getHeight();
            float height = mHeight * width / mWidth;
            Drawable drawable = newBuilder()
                    .setSizePx(width, height)
                    .setNormal(new BitmapDrawable(bitmap))
                    .buildDrawable();
            bitmap = toBitmap(drawable);
        }
        return bitmap;
    }

    public static Bitmap getBitmapByHeight(Bitmap bitmap, int height) {
        if (bitmap != null) {
            float mWidth = bitmap.getWidth();
            float mHeight = bitmap.getHeight();
            float width = mWidth * height / mHeight;
            Drawable drawable = newBuilder()
                    .setSizePx(width, height)
                    .setNormal(new BitmapDrawable(bitmap))
                    .buildDrawable();
            bitmap = toBitmap(drawable);
        }
        return bitmap;
    }

    public static long getBitmapLength(Bitmap bitmap) {
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    /**
     * 以宽为基础缩放
     *
     * @param drawable
     * @param width
     * @return
     */
    public static Drawable setSizeForWidth(Drawable drawable, float width) {
        if (drawable != null && drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) {
            float dWidth = drawable.getIntrinsicWidth();
            float dHeight = drawable.getIntrinsicHeight();
            float height = dHeight / dWidth * width;
            return setSize(drawable, (int) width, (int) height);
        }
        return drawable;
    }

    /**
     * 以高为基础缩放
     *
     * @param drawable
     * @param height
     * @return
     */
    public static Drawable setSizeForHeight(Drawable drawable, float height) {
        if (drawable != null && drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) {
            float dWidth = drawable.getIntrinsicWidth();
            float dHeight = drawable.getIntrinsicHeight();
            float width = dWidth / dHeight * height;
            return setSize(drawable, (int) width, (int) height);
        }
        return drawable;
    }

    /**
     * 设置比例
     *
     * @param drawable
     * @param width
     * @param height
     * @return
     */
    public static Drawable setSize(Drawable drawable, int width, int height) {
        if (drawable != null) {
            Bitmap oldBmp = GYDisplayUtils.toBitmap(drawable);
            Bitmap newBmp = Bitmap.createScaledBitmap(oldBmp, width, height, true);
            return new BitmapDrawable(newBmp);
        }
        return null;
    }

    /**
     * 将px值转换为dip或dp值，保证尺寸大小不变
     *
     * @param context
     * @param pxValue （DisplayMetrics类中属性density）
     * @return
     */
    public static int px2dp(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    /**
     * 将dip或dp值转换为px值，保证尺寸大小不变
     *
     * @param context
     * @param dipValue （DisplayMetrics类中属性density）
     * @return
     */
    public static int dp2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    /**
     * 将px值转换为sp值，保证文字大小不变
     *
     * @param context
     * @param pxValue （DisplayMetrics类中属性scaledDensity）
     * @return
     */
    public static int px2sp(Context context, float pxValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }

    /**
     * 将sp值转换为px值，保证文字大小不变
     *
     * @param context
     * @param spValue （DisplayMetrics类中属性scaledDensity）
     * @return
     */
    public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

    /**
     * 图片转成string
     *
     * @param bitmap
     * @return
     */
    public static String toString(Bitmap bitmap) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();// outputstream
        bitmap.compress(Bitmap.CompressFormat.PNG, 5, baos);
        byte[] bytes = baos.toByteArray();// 转为byte数组
        return Base64.encodeToString(bytes, Base64.DEFAULT);
    }

    /**
     * string转成bitmap
     *
     * @param str
     */
    public static Bitmap toBitmap(String str) {
        try {
            byte[] bytes = Base64.decode(str, Base64.DEFAULT);
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        } catch (Exception e) {
            return null;
        }
    }
}
